{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "#请先运行此代码\n",
    "from IPython.core.interactiveshell import InteractiveShell\n",
    "InteractiveShell.ast_node_interactivity = \"all\" \n",
    "#这玩意可以让代码块分行输出"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 高阶函数"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 函数名也是变量\n",
    "* 那么函数名是什么呢？函数名其实就是指向函数的变量！对于abs()这个函数，完全可以把函数名abs看成变量，它指向一个可以计算绝对值的函数！如果把abs指向其他对象，会有什么情况发生？"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "ename": "TypeError",
     "evalue": "'int' object is not callable",
     "output_type": "error",
     "traceback": [
      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[1;31mTypeError\u001b[0m                                 Traceback (most recent call last)",
      "\u001b[1;32m~\\AppData\\Local\\Temp/ipykernel_2804/2574985616.py\u001b[0m in \u001b[0;36m<module>\u001b[1;34m\u001b[0m\n\u001b[0;32m      1\u001b[0m \u001b[0mabs\u001b[0m \u001b[1;33m=\u001b[0m \u001b[1;36m10\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 2\u001b[1;33m \u001b[0mabs\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m-\u001b[0m\u001b[1;36m10\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;31m#abs现在不是函数了哦，现在是一个整数\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m",
      "\u001b[1;31mTypeError\u001b[0m: 'int' object is not callable"
     ]
    }
   ],
   "source": [
    "abs = 10\n",
    "abs(-10)#abs现在不是函数了哦，现在是一个整数，所以会报错"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 传入函数"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "11\n"
     ]
    }
   ],
   "source": [
    "def abs(x):#因为上面把abs搞坏了，这里就随便写一个\n",
    "    if x>=0:\n",
    "        return x\n",
    "    else:\n",
    "        return -x\n",
    "\n",
    "def add(x, y, f):\n",
    "    return f(x) + f(y)\n",
    "\n",
    "print(add(-5, 6, abs))#运算结果就是abs（-5）+abs（6）"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### map/reduce"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* 我们先看map。map()函数接收两个参数，一个是函数，一个是Iterable，map将传入的函数依次作用到序列的每个元素，并把结果作为新的Iterator返回"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[1, 4, 9, 16, 25, 36, 49, 64, 81]"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "def f(x):\n",
    "    return x * x\n",
    "r = map(f, [1, 2, 3, 4, 5, 6, 7, 8, 9])#把后面这一堆数传进去，然后进行输出\n",
    "list(r)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* list所有数字转为字符串"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['1', '2', '3', '4', '5', '6', '7', '8', '9']"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "list(map(str, [1, 2, 3, 4, 5, 6, 7, 8, 9]))#简单易懂嘛"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* 比方说对一个序列求和，就可以用reduce实现：\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "25"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "text/plain": [
       "25"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from functools import reduce\n",
    "def add(x, y):\n",
    "     return x + y\n",
    "\n",
    "reduce(add, [1, 3, 5, 7, 9])#reduce(f, [x1, x2, x3, x4]) = f(f(f(x1, x2), x3), x4)\n",
    "sum([1, 3, 5, 7, 9])#当然还是用sum更好啦"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* 但是如果要把序列[1, 3, 5, 7, 9]变换成整数13579，reduce就可以派上用场："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from functools import reduce\n",
    "def fn(x, y):\n",
    "    return x * 10 + y\n",
    "\n",
    "reduce(fn, [1, 3, 5, 7, 9])#reduce(f, [x1, x2, x3, x4]) = f(f(f(x1, x2), x3), x4)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* 一个str2int的函数\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from functools import reduce\n",
    "\n",
    "DIGITS = {'0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9}\n",
    "\n",
    "def str2int(s):\n",
    "    def fn(x, y):#把数字拼接起来\n",
    "        return x * 10 + y\n",
    "    def char2num(s):\n",
    "        return DIGITS[s]\n",
    "    return reduce(fn, map(char2num, s))#先通过map把字符转换成单个数字，然后在通过fn拼接起来"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# filter\n",
    "* 把一个序列中的空字符串删掉，可以这么写："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<filter at 0x17ec0387160>"
      ]
     },
     "execution_count": 16,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "text/plain": [
       "['A', 'B', 'C']"
      ]
     },
     "execution_count": 16,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "def not_empty(s):\n",
    "    return s and s.strip()#s.strip()是取出首尾空格的作用，如果中间有参数的话，如s.strip( '0' )是去除首尾字符 0 \n",
    "\n",
    "filter(not_empty, ['A', '', 'B', None, 'C', '  '])#filter()函数返回的是一个Iterator,要强迫filter()完成计算结果，需要用list()函数获得所有结果并返回list\n",
    "list(filter(not_empty, ['A', '', 'B', None, 'C', '  ']))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* 用埃氏筛法求素数"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2\n",
      "3\n",
      "5\n",
      "7\n",
      "11\n",
      "13\n",
      "17\n",
      "19\n"
     ]
    }
   ],
   "source": [
    "def _odd_iter():#构造一个从3开始的奇数序列，因为从除了2的其他偶数都不是素数\n",
    "    n = 1\n",
    "    while True:\n",
    "        n = n + 2\n",
    "        yield n\n",
    "def _not_divisible(n):#定义一个筛选函数\n",
    "    return lambda x: x % n > 0#返回值为true保留，返回值为false丢弃\n",
    "\n",
    "def primes():#素数生成器\n",
    "    yield 2#第一个素数是n\n",
    "    it = _odd_iter() # 初始序列\n",
    "    while True:\n",
    "        n = next(it) # 返回序列的第一个数\n",
    "        yield n\n",
    "        it = filter(_not_divisible(n), it) # 构造新序列\n",
    "\n",
    "for n in primes():#输出前20的素数\n",
    "    if n < 20:\n",
    "        print(n)\n",
    "    else:\n",
    "        break"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### sorted"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[-21, -12, 5, 9, 36]"
      ]
     },
     "execution_count": 21,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "text/plain": [
       "[5, 9, -12, -21, 36]"
      ]
     },
     "execution_count": 21,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "text/plain": [
       "['about', 'bob', 'Credit', 'Zoo']"
      ]
     },
     "execution_count": 21,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "text/plain": [
       "['Zoo', 'Credit', 'bob', 'about']"
      ]
     },
     "execution_count": 21,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "sorted([36, 5, -12, 9, -21])#普通排序\n",
    "sorted([36, 5, -12, 9, -21], key=abs)#按绝对值排序\n",
    "sorted(['bob', 'about', 'Zoo', 'Credit'], key=str.lower)#忽略大小写的排序，不然按ascll码来说Z比a小\n",
    "sorted(['bob', 'about', 'Zoo', 'Credit'], key=str.lower,reverse=True)#将排序结果反转"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 返回函数（看不懂）"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* 我们来实现一个可变参数的求和。通常情况下，求和的函数是这样定义的："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def calc_sum(*args):\n",
    "    ax = 0\n",
    "    for n in args:\n",
    "        ax = ax + n\n",
    "    return ax"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* 但是，如果不需要立刻求和，而是在后面的代码中，根据需要再计算怎么办？可以不返回求和的结果，而是返回求和的函数："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 65,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<function __main__.lazy_sum.<locals>.sum()>"
      ]
     },
     "execution_count": 65,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "def lazy_sum(*args):#加*号是因为这是可变参数\n",
    "    def sum():\n",
    "        ax = 0\n",
    "        for n in args:\n",
    "            ax = ax + n\n",
    "        return ax\n",
    "    return sum #lazy_sum在这边返回，所以得到的是sum\n",
    "\n",
    "f = lazy_sum(1, 3, 5, 7, 9)\n",
    "f"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* 当我们调用lazy_sum()时，返回的并不是求和结果，而是求和函数："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<function __main__.lazy_sum.<locals>.sum()>"
      ]
     },
     "execution_count": 34,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "text/plain": [
       "25"
      ]
     },
     "execution_count": 34,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "text/plain": [
       "25"
      ]
     },
     "execution_count": 34,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "f = lazy_sum(1, 3, 5, 7, 9)\n",
    "f\n",
    "f()\n",
    "lazy_sum(1, 3, 5, 7, 9)()#后面一个括号里面是相当于sum()的值吗？"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* 在这个例子中，我们在函数lazy_sum中又定义了函数sum，并且，内部函数sum可以引用外部函数lazy_sum的参数和局部变量，当lazy_sum返回函数sum时，相关参数和变量都保存在返回的函数中，这种称为“闭包（Closure）”的程序结构拥有极大的威力。\n",
    "\n",
    "* 请再注意一点，当我们调用lazy_sum()时，每次调用都会返回一个新的函数，即使传入相同的参数："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "False"
      ]
     },
     "execution_count": 29,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "f1 = lazy_sum(1, 3, 5, 7, 9)\n",
    "f2 = lazy_sum(1, 3, 5, 7, 9)\n",
    "f1==f2"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* 另一个需要注意的问题是，返回的函数并没有立刻执行，而是直到调用了f()才执行。我们来看一个例子："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 47,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<function __main__.count.<locals>.f()>"
      ]
     },
     "execution_count": 47,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "text/plain": [
       "[<function __main__.count.<locals>.f()>,\n",
       " <function __main__.count.<locals>.f()>,\n",
       " <function __main__.count.<locals>.f()>]"
      ]
     },
     "execution_count": 47,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "text/plain": [
       "9"
      ]
     },
     "execution_count": 47,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "text/plain": [
       "9"
      ]
     },
     "execution_count": 47,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "text/plain": [
       "9"
      ]
     },
     "execution_count": 47,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "def count():\n",
    "    fs = []\n",
    "    for i in range(1, 4):\n",
    "        def f():\n",
    "             return i*i\n",
    "        fs.append(f)\n",
    "    return fs\n",
    "\n",
    "f1, f2, f3 = count()\n",
    "\n",
    "f1#这样才返回一个fn\n",
    "count()#这样返回3个fn\n",
    "f1()\n",
    "f2()\n",
    "f3()\n",
    "#全部都是9！原因就在于返回的函数引用了变量i，但它并非立刻执行。等到3个函数都返回时，它们所引用的变量i已经变成了3，因此最终结果为9。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**返回闭包时牢记一点：返回函数不要引用任何循环变量，或者后续会发生变化的变量。**"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### nonlocal"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* 使用闭包，就是内层函数引用了外层函数的局部变量。如果只是读外层变量的值，我们会发现返回的闭包函数调用一切正常："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 48,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1\n",
      "1\n"
     ]
    }
   ],
   "source": [
    "def inc():\n",
    "    x = 0\n",
    "    def fn():\n",
    "        # 仅读取x的值:\n",
    "        return x + 1\n",
    "    return fn\n",
    "\n",
    "f = inc()\n",
    "print(f()) # 1\n",
    "print(f()) # 1"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* 但是，如果对外层变量赋值，由于Python解释器会把x当作函数fn()的局部变量，它会报错："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 49,
   "metadata": {},
   "outputs": [
    {
     "ename": "UnboundLocalError",
     "evalue": "local variable 'x' referenced before assignment",
     "output_type": "error",
     "traceback": [
      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[1;31mUnboundLocalError\u001b[0m                         Traceback (most recent call last)",
      "\u001b[1;32m~\\AppData\\Local\\Temp/ipykernel_2804/458659968.py\u001b[0m in \u001b[0;36m<module>\u001b[1;34m\u001b[0m\n\u001b[0;32m      8\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m      9\u001b[0m \u001b[0mf\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0minc\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m---> 10\u001b[1;33m \u001b[0mprint\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mf\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m)\u001b[0m \u001b[1;31m# 1\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m     11\u001b[0m \u001b[0mprint\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mf\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m)\u001b[0m \u001b[1;31m# 2\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;32m~\\AppData\\Local\\Temp/ipykernel_2804/458659968.py\u001b[0m in \u001b[0;36mfn\u001b[1;34m()\u001b[0m\n\u001b[0;32m      3\u001b[0m     \u001b[1;32mdef\u001b[0m \u001b[0mfn\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m      4\u001b[0m         \u001b[1;31m# nonlocal x\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 5\u001b[1;33m         \u001b[0mx\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mx\u001b[0m \u001b[1;33m+\u001b[0m \u001b[1;36m1\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m      6\u001b[0m         \u001b[1;32mreturn\u001b[0m \u001b[0mx\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m      7\u001b[0m     \u001b[1;32mreturn\u001b[0m \u001b[0mfn\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;31mUnboundLocalError\u001b[0m: local variable 'x' referenced before assignment"
     ]
    }
   ],
   "source": [
    "def inc():\n",
    "    x = 0\n",
    "    def fn():\n",
    "        # nonlocal x\n",
    "        x = x + 1\n",
    "        return x\n",
    "    return fn\n",
    "\n",
    "f = inc()\n",
    "print(f()) # 1\n",
    "print(f()) # 2"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* 原因是x作为局部变量并没有初始化，直接计算x+1是不行的。但我们其实是想引用inc()函数内部的x，所以需要在fn()函数内部加一个nonlocal x的声明。加上这个声明后，解释器把fn()的x看作外层函数的局部变量，它已经被初始化了，可以正确计算x+1。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 52,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1\n",
      "2\n"
     ]
    }
   ],
   "source": [
    "def inc():#加上nonlocal\n",
    "    x = 0\n",
    "    def fn():\n",
    "        nonlocal x\n",
    "        x = x + 1\n",
    "        return x\n",
    "    return fn\n",
    "\n",
    "f = inc()\n",
    "print(f()) # 1\n",
    "print(f()) # 2"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* 一个函数可以返回一个计算结果，也可以返回一个函数。\n",
    "\n",
    "* 返回一个函数时，牢记该函数并未执行，返回函数中不要引用任何可能会变化的变量。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 匿名函数\n",
    "* 一个好用的匿名函数"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "list(map(lambda x: x * x, [1, 2, 3, 4, 5, 6, 7, 8, 9]))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "通过对比可以看出，匿名函数lambda x: x * x实际上就是："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 53,
   "metadata": {},
   "outputs": [],
   "source": [
    "def f(x):\n",
    "    return x * x"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* 普通写法"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 55,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[1, 3, 5, 7, 9, 11, 13, 15, 17, 19]"
      ]
     },
     "execution_count": 55,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "def is_odd(n):\n",
    "    return n % 2 == 1\n",
    "\n",
    "L = list(filter(is_odd, range(1, 20)))\n",
    "L"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* 匿名函数写法"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 56,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[1, 3, 5, 7, 9, 11, 13, 15, 17, 19]"
      ]
     },
     "execution_count": 56,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "def is_odd(n):\n",
    "    L = list(filter(lambda n:n % 2 ==1, range(1, 20)))\n",
    "L"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 装饰器"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 57,
   "metadata": {},
   "outputs": [],
   "source": [
    "def now():\n",
    "    print('2022-1-14')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* 现在，假设我们要增强now()函数的功能，比如，在函数调用前后自动打印日志，但又不希望修改now()函数的定义，这种在代码运行期间动态增加功能的方式，称之为“装饰器”（Decorator）。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 72,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "call now():\n",
      "132\n"
     ]
    }
   ],
   "source": [
    "def log(func):\n",
    "    def wrapper(*args, **kw):\n",
    "        print('call %s():' % func.__name__)\n",
    "        return func(*args, **kw)#这边就是执行原本的now\n",
    "    return wrapper\n",
    "\n",
    "@log #相当于是now = log(now)\n",
    "def now(s):#所以这边的s是传给wrapper，wrapper()函数的参数定义是(*args, **kw)，因此，wrapper()函数可以接受任意参数的调用。在wrapper()函数内，首先打印日志，再紧接着调用原始函数。\n",
    "    print(s)\n",
    "\n",
    "now(\"132\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* 自定义log的文本"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 63,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "运行函数中： now():\n",
      "你好呀\n"
     ]
    }
   ],
   "source": [
    "def log(text):\n",
    "    def decorator(func):\n",
    "        def wrapper(*args, **kw):\n",
    "            print('%s %s():' % (text, func.__name__))\n",
    "            return func(*args, **kw)\n",
    "        return wrapper#这边进入第三层\n",
    "    return decorator#这边进入第二层\n",
    "\n",
    "@log('运行函数中：')#效果是再嵌套一层，now = log('execute')(now)\n",
    "def now():\n",
    "    print('你好呀')\n",
    "\n",
    "now()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* 以上两种decorator的定义都没有问题，但还差最后一步。因为我们讲了函数也是对象，它有__name__等属性，但你去看经过decorator装饰之后的函数，它们的__name__已经从原来的'now'变成了'wrapper'："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 73,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'wrapper'"
      ]
     },
     "execution_count": 73,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "now.__name__# 因为wrapper是执行now的功能的"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* 这样写不好，所以一个完整的decorator的写法是"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import functools\n",
    "\n",
    "def log(func):\n",
    "    @functools.wraps(func)#反正记得加这句话就行了\n",
    "    def wrapper(*args, **kw):\n",
    "        print('call %s():' % func.__name__)\n",
    "        return func(*args, **kw)\n",
    "    return wrapper\n",
    "\n",
    "#带参数的\n",
    "import functools\n",
    "\n",
    "def log(text):\n",
    "    def decorator(func):\n",
    "        @functools.wraps(func)#反正记得加这句话就行了\n",
    "        def wrapper(*args, **kw):\n",
    "            print('%s %s():' % (text, func.__name__))\n",
    "            return func(*args, **kw)\n",
    "        return wrapper\n",
    "    return decorator"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 偏函数"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* functools.partial的作用就是，把一个函数的某些参数给固定住（也就是设置默认值），返回一个新的函数，调用这个新函数会更简单。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 82,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "64"
      ]
     },
     "execution_count": 82,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "text/plain": [
       "64"
      ]
     },
     "execution_count": 82,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "text/plain": [
       "85"
      ]
     },
     "execution_count": 82,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "text/plain": [
       "1000000"
      ]
     },
     "execution_count": 82,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import functools\n",
    "\n",
    "int('1000000', base=2)#二进制转换\n",
    "\n",
    "int2 = functools.partial(int, base=2)\n",
    "int2('1000000')#这样写方便多了\n",
    "int2('1010101')\n",
    "\n",
    "int2('1000000', base=10)#你非要10进制也行\n"
   ]
  }
 ],
 "metadata": {
  "interpreter": {
   "hash": "2e918aaa81d99c652401bdd1a0c185581595fb477ac919641bd65261b5d7782a"
  },
  "kernelspec": {
   "display_name": "Python 3.9.7 64-bit ('base': conda)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.7"
  },
  "orig_nbformat": 4
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
